/*
 * Copyright (c) 2009 Nokia Corporation.
 */

/**
  * This is run after the the web page has been loaded (possibly before rendering).
  * $(document).ready documented here:
  * http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
  */
$(document).ready(function() {
  try {
    /**
     *
     */
    console.debug("Init started.");
    var db = openDatabase("CartoonReader",
                          "1.0",
                          "CartoonReader example",
                          200000);
    if (!db) {
      alert("Failed to open the database on disk.  This is probably because the version was bad or there is not enough space left in this domain's quota");
    }
    if(window.appWindow) {
      window.minimize = appWindow.minimize;
    }
    var platform = "";
    if(window.platformResolver) {
      platform = window.platformResolver.platform();
    }
    var elements = { window: window,
                     document: window.document,
                     headerContainer: $("#headerContainer"),
                     navigation: $("#topNavigation"),
                     cartoonList: $("#cartoonList"),
                     newCartoonSourceSection: $("#newCartoonSourceSection"),
                     images: $("img"),
                     body: $("body"),
                     html: $("html"),
                     navLiButtons: $("nav li button"),
                     cartoonReader: $("#cartoonReader")};
    var helpers = { dndHelper: new DnDHelper(),
                    cartoonDataFetcher: new CartoonDataFetcher(new FeedUpdateBroker(),
                                                               new CartoonParser(),
                                                               new FeedResolver())
                  };
    helpers.maemoHelper = new MaemoHelper(window,
                                          helpers.dndHelper);
    window.CartoonManager = new CartoonManager(db,
                                               window,
                                               elements,
                                               helpers,
                                               platform);
    console.debug("Init finished.");
  }
  catch(e) {
    console.error(e);
    alert(e);
  }
});

function CartoonManager(db,
                        applicationWindow,
                        elements,
                        helpers,
                        platform) {

  this.C_SINGLE_CARTOON_VIEW_URL = "../html/cartoon-view.html";
  this.PLATFORM = platform;

  this.m_window = applicationWindow;
  this.m_helpers = helpers;
  this.m_elementCreator = new CartoonManager.ElementCreator(elements.document, 
                                                            helpers.dndHelper);
  this.m_view = new CartoonManager.View(elements);
  this.m_backend = new CartoonManagerBackend(db);
  var subscribers = [];
  subscribers.push(this.m_view);
  subscribers.push(this.m_backend);
  subscribers.push(this);
  this.m_model = new CartoonManager.Model(subscribers);
  var cartoonSourceResultAdapter = new CartoonSourceResultAdapter({ that: this.m_model,
                                                                    callback: this.m_model.receiveCartoonSources});
  var additionAdapter = new CartoonAdditionAdapter(this.m_backend,
                                                   {that: this.m_model,
                                                    callback: this.m_model.addCartoonSource});
  this.m_backend.registerGetCartoonSourcesAdapter(cartoonSourceResultAdapter);
  this.m_backend.registerAddCartoonSourceAdapter(additionAdapter);

  this.setup(this.m_view,
             helpers,
             elements,
             platform);
  this.m_backend.getCartoonSources();
}

CartoonManager.prototype = {
  setup: function(view,
                  helpers,
                  elements,
                  platform) {
    view.hideAddCartoonSource(true);
    this.bindBackButton(elements.navigation.find("#backButton"));
    this.bindAddButton(elements.navigation.find("#addButton"));
    this.bindAddFeedButton(elements.newCartoonSourceSection.find("#addFeedButton"));
    this.bindCancelAddFeedButton(elements.newCartoonSourceSection.find("#cancelAddFeedButton"));
    helpers.dndHelper.disableDragging(elements.images);
    if(platform === "MAEMO") {
      helpers.maemoHelper.createTaskSwitcher(elements.headerContainer);
      helpers.maemoHelper.setFontSizeTo(elements.body, "1.25em");
    }
  },
  bindBackButton: function(backButton) {
    var self = this;
    backButton.click(function () {
      self.goToSingleCartoonView(); 
    });
  },
  bindAddButton: function(addButton) {
    var self = this;
    addButton.click(function () {
      var cartoonSourceState = self.m_view.getCartoonSourceHidden();
      self.m_view.hideAddCartoonSource(!cartoonSourceState);
    });
  },
  bindCancelAddFeedButton: function(cancelAddFeedButton) {
    var self = this;
    cancelAddFeedButton.click(function () {
      self.m_helpers.cartoonDataFetcher.abort();
      self.m_view.hideAddCartoonSource(true);
    });
  },
  bindAddFeedButton: function(addFeedButton) {
    var self = this;
    addFeedButton.click(function () { 
      self.addFeedButtonClicked() 
    });
  },
  addFeedButtonClicked: function() {
    var cartoonSourceAddState = this.m_view.getCartoonSourceAdditionState();
    if(cartoonSourceAddState !== 'loading') {
      this.m_view.changeCartoonSourceAdditionState('loading');
      var newCartoonSourceSection = this.m_view.getElement("newCartoonSourceSection");
      var newCartoonSourceURL = newCartoonSourceSection.find("#newCartoonSourceURL");
      var url = newCartoonSourceURL.attr("value");
      if(url.search(/http:\/\//) == -1) {
        url = "http://" + url;
      }
      this.m_helpers.cartoonDataFetcher.getDataFromURL(url, {cartoonReceiver: { that: this,
                                                                                callback: this.receiveCartoons,
                                                                                errorCallback: this.receiveCartoonParsingError},
                                                             errorReceiver: { that: this,
                                                                              callback: this.receiveCartoonParsingError}
                                                             });
    }
  },
  receiveCartoons: function(cartoons) {
    this.m_view.hideAddCartoonSource(true);
    this.m_model.createCartoonSource(cartoons.URL,
                                     cartoons.title);
  },
  receiveCartoonParsingError: function(URL, error) {
    this.m_view.displayNewCartoonError("Couldn't find cartoons from this URL: " + URL);
  },
  selectButtonClicked: function(target, event) {
    this.m_tempCartoonSource = this.findCartoonSourceId(target);
    this.m_model.setActiveCartoonSource(this.m_tempCartoonSource);
  },
  cartoonSourcesUpdated: function(cartoonSources) {
    for(var i=0; i < cartoonSources.length; i++) {
      if(cartoonSources[i].getActiveBoolean()) {
        var that = this;
        this.m_window.setTimeout(function(){ that.goToSingleCartoonView(); },
                                 700);
      }
    }
  },
  goToSingleCartoonView: function() {
    var window = this.m_window;
    var url = this.C_SINGLE_CARTOON_VIEW_URL;
    if(this.PLATFORM !== "MAEMO" &&
       this.PLATFORM !== "SYMBIAN") {
      this.m_view.fadeOut("slow",
                          function() {window.location = url; });
    }
    else if (this.PLATFORM === "SYMBIAN") {
      $("#cartoons").hide();
      window.location = url;
    }
    else {
      window.location = url;
    }
  },
  removeButtonClicked: function(target, event) {
    var id = this.findCartoonSourceId(target);
    this.m_model.removeCartoonSource(id);
  },
  addCartoonSourceToView: function(cartoonSource) {
    var self = this;
    selectButtonHandler = function (event) { self.selectButtonClicked($(this), event) };
    removeButtonHandler = function (event) { self.removeButtonClicked($(this), event) };
    var cartoonSourceLi = this.m_elementCreator.createManageableCartoonSource(cartoonSource,
                                                                              selectButtonHandler,
                                                                              removeButtonHandler);
    this.m_view.addCartoonSourceElement(cartoonSourceLi);
  },
  findCartoonSourceId: function(target) {
    var parent = $(target.parent().parent().get(0)); 
	// table > form > tr [- some tr contains hidden inputs] > td > button
    var idElement = parent.find("input[name=id]");
    var id = new Number(idElement.attr("value"));
    return id;
  },
  receiveModelChanges: function(changes) {
    if("added" in changes) {
      this.addCartoonSourceToView(changes.added.cartoonSource);
    }
    if("updated" in changes &&
       !("removed" in changes)) {
      if(changes.updated.cartoonSources !== undefined) {
        this.cartoonSourcesUpdated(changes.updated.cartoonSources);
      }
    }
  }
};

CartoonManager.Model = function(subscribers) {
  this.m_subscribers = subscribers;
  this.m_cartoonSources = {};
};

CartoonManager.Model.prototype = {
  receiveCartoonSources: function(cartoonSources) {
    for(var i = 0; i < cartoonSources.length; i++) {
      this.addCartoonSource(cartoonSources[i]);
    }
  },
  setActiveCartoonSource: function(id) {
    if(id in this.m_cartoonSources) {
      var oldActive = this.findActiveCartoonSource();
	  if (id == oldActive.id) {
        var activeCartoonSource = this.m_cartoonSources[id];
	    // Go directly to the single cartoon view
        var changes = { updated: {
                          cartoonSources: [activeCartoonSource]
                        }
                      };
        this.informSubscribers(changes);
	  }
	  else {
        this.m_cartoonSources[oldActive.id].setActive(false);
        this.m_cartoonSources[id].setActive(true);
        var oldActiveCartoonSource = this.m_cartoonSources[oldActive.id];
        var activeCartoonSource = this.m_cartoonSources[id];
        var changes = { updated: {
                          cartoonSources: [oldActiveCartoonSource,
                                           activeCartoonSource]
                        }
                      };
        this.informSubscribers(changes);
	  }
    }
  },
  findActiveCartoonSource: function() {
    var foundCartoonSource = { id: -1, cartoonSource: undefined };
    for(var i in this.m_cartoonSources) {
      if(this.m_cartoonSources[i].getActiveBoolean()) {
        foundCartoonSource.cartoonSource = this.m_cartoonSources[i];
        foundCartoonSource.id = i;
        break;
      }
    }
    return foundCartoonSource;
  },
  createCartoonSource: function(url, name) {
    var cartoonSource = new CartoonSource();
    cartoonSource.setUrl(url);
    cartoonSource.setName(name);
    cartoonSource.setActive(false);
    var changes = { toBeAdded: {
                      cartoonSource: cartoonSource
                    }
                  };
    this.informSubscribers(changes);
  },
  addCartoonSource: function(cartoonSource) {
    this.m_cartoonSources[cartoonSource.getId()] = cartoonSource;
    var changes = { added: {
                      cartoonSource: cartoonSource
                    }
                  };
    this.informSubscribers(changes);
  },
  getCartoonSource: function(id) {
    return this.m_cartoonSources[id];
  },
  removeCartoonSource: function(id) {
    if(this.m_cartoonSources[id] !== undefined) {
      var toBeDeleted = this.m_cartoonSources[id];
      delete this.m_cartoonSources[id];
	  var changes;
	  if (toBeDeleted.getActive()) {
		for(var i in this.m_cartoonSources) {
		  var firstSource = this.m_cartoonSources[i];
		}
		firstSource.setActive(true);
        changes = { removed: toBeDeleted,
                      updated: {
                        cartoonSources: [firstSource]
                      }
                    };
	  }
	  else {
        changes = { removed: toBeDeleted
                    };
	  }

      this.informSubscribers(changes);
    }
  },
  informSubscribers: function(changes) {
    for (var i=0; i<this.m_subscribers.length; i++) {
      this.m_subscribers[i].receiveModelChanges(changes);
    }
  }
};

CartoonManager.View = function(elements) {
  this.m_elements = elements;
  this.setup(this.m_elements);
  this.C_CARTOON_ACTIVE_ICON = "../images/active.png";
  this.C_CARTOON_INACTIVE_ICON = "../images/inactive.png";
  this.C_CARTOON_ACTIVITY_ERROR = "../images/error-icon.png";
  this.C_CARTOON_ACTIVITY_LOADING = "../images/loading-small.gif";
};

CartoonManager.View.prototype = {
  setup: function(elements) {
    elements.newCartoonSourceSection.hide();
    this.fadeIn("slow");
  },
  fadeIn: function(speed, callback) {
    this.m_elements.body.fadeIn(speed, callback);
  },
  fadeOut: function(speed, callback) {
    this.m_elements.body.fadeOut(speed, callback);
  },
  getElement: function(elementName) {
    return this.m_elements[elementName];
  },
  getCartoonSourceHidden: function() {
    var displayed = this.m_elements.newCartoonSourceSection.css('display');
    return (displayed === 'none');
  },
  hideAddCartoonSource: function(hide) {
    if(hide) {
      this.changeCartoonSourceAdditionState("");
      var input = this.m_elements.newCartoonSourceSection.find("#newCartoonSourceURL");
      input.attr("value", "");
      this.m_elements.newCartoonSourceSection.fadeOut('slow');
    }
    else {
      var input = this.m_elements.newCartoonSourceSection.find("#newCartoonSourceURL");
      this.m_elements.newCartoonSourceSection.fadeIn('slow',
                                                     function(){input.focus();});
    }
  },
  addCartoonSourceElement: function(element) {
    element.hide();
    this.m_elements.cartoonList.append(element);
    element.fadeIn('slow');
  },
  displayNewCartoonError: function(error) {
    $("#newCartoonSourceURL").focus();
    var errorDiv = this.m_elements.newCartoonSourceSection.find("#newCartoonSourceError");
    errorDiv.append("<p>" + error + "</p>");
    this.changeCartoonSourceAdditionState("error");
    errorDiv.slideDown('slow').delay(2000).slideUp('slow', function() {$(this).empty();});
  },
  getCartoonSourceAdditionState: function() {
    var state = "";
    var addActivity = this.m_elements.newCartoonSourceSection.find("#newCartoonAddActivity");
    var url = addActivity.attr("src");
    if(url === this.C_CARTOON_ACTIVITY_ERROR) {
      state = "error";
    }
    if(url === this.C_CARTOON_ACTIVITY_LOADING) {
      state = "loading";
    }
    return state;
  },
  changeCartoonSourceAdditionState: function(state) {
    if(state === '') {
      this.changeAddActivityImageProperties("",
                                            "",
                                            true);
    }
    if(state === 'error') {
      this.changeAddActivityImageProperties(this.C_CARTOON_ACTIVITY_ERROR,
                                            "Error",
                                            false);
    }
    if(state === 'loading') {
      this.changeAddActivityImageProperties(this.C_CARTOON_ACTIVITY_LOADING,
                                            "Loading...",
                                            false);
    }
  },
  changeAddActivityImageProperties: function(src, alt, hide) {
    var addActivity = this.m_elements.newCartoonSourceSection.find("#newCartoonAddActivity");
    addActivity.attr("src", src);
    addActivity.attr("alt", alt);
    if(hide) {
      addActivity.hide('slow');
    }
    else {
      addActivity.show('slow');
    }
  },
  changeCartoonSourceActivity: function(id, activity) {
    var cartoonSourceLi = this.findCartoonSourceLi(id);
    var activeIcon = cartoonSourceLi.find(".activeIcon");
    if(activity) {
      activeIcon.attr("src", this.C_CARTOON_ACTIVE_ICON);
      activeIcon.attr("alt", "active");
    }
    else {
      activeIcon.attr("src", this.C_CARTOON_INACTIVE_ICON);
      activeIcon.attr("alt", "inactive");
    }
  },
  handleRemoved: function(removed) {
    var cartoonSourceLi = this.findCartoonSourceLi(removed.getId());
    cartoonSourceLi.hide('slow', 
                         function() { $(this).remove();});
  },
  handleUpdated: function(updated) {
    if(updated.cartoonSources !== undefined) {
      var cartoonSources = updated.cartoonSources;
      for(var i=0; i<cartoonSources.length; i++) {
        this.updateCartoonSource(cartoonSources[i]);
      }
    }
  },
  updateCartoonSource: function(cartoonSource) {
    this.changeCartoonSourceActivity(cartoonSource.getId(),
                                     cartoonSource.getActiveBoolean());
  },
  
  findCartoonSourceLi: function(id) {
    var idInput = this.m_elements.cartoonList.find("input[value=" +id+"]");
    var cartoonSourceLi = $(idInput.parents("li").get(0));
    return cartoonSourceLi;
  },
  receiveModelChanges: function(changes) {
    if("removed" in changes) {
      this.handleRemoved(changes.removed);
    }
    if("updated" in changes) {
      this.handleUpdated(changes.updated);
    }
  }
};

CartoonManager.ElementCreator = function(document, dndHelper) {
  this.m_document = document;
  this.m_dndHelper = dndHelper;
};

CartoonManager.ElementCreator.prototype = {
  createManageableCartoonSource: function(cartoonSource,
                                          selectButtonHandler,
                                          removeButtonHandler) {
    var html = "<li>" +
               "<form>" +
               "<table><tbody>" +
			   "<tr>" +
			   "<td class=\"activeLabelTd\">" +
               "<input type=\"hidden\" name=\"id\" value=\"\" ></input>" +
               "<input type=\"hidden\" name=\"url\" value=\"\" ></input>" +
			   "<label for=\"\"><img class=\"activeIcon\" src=\"\" /></label>" +
			   "</td>" +
               "<td class=\"feedButtonTd\"><button type=\"button\" class=\"feedButton\" name=\"\"></button></td>" +
               "<td class=\"removeButtonTd\"><button type=\"button\" class=\"removeButtonTd\" name=\"remove\"><img src=\"../images/icon_trash.png\" /></button></td>" +
               "</tr>" +
			   "</tbody></table>" +
			   "</form>" +
               "</li>";
    var cartoonSourceElement = $(html, this.m_document);

    var label = cartoonSourceElement.find("label");
    label.attr("for", "select-"+cartoonSource.getId());

    var activeIcon = cartoonSourceElement.find("img[class=activeIcon]");
    activeIcon.attr("src", (cartoonSource.getActiveBoolean() ?
                            "../images/active.png" : "../images/inactive.png"));
    this.m_dndHelper.disableDragging(activeIcon);

    var idElement = cartoonSourceElement.find("input[name=id]");
    idElement.attr("value", cartoonSource.getId());

    var urlElement = cartoonSourceElement.find("input[name=url]");
    urlElement.attr("value", cartoonSource.getUrl());

    var feedButton = cartoonSourceElement.find("button[class=feedButton]");
    feedButton.attr("id", "select-"+cartoonSource.getId());
    feedButton.attr("name", cartoonSource.getId());
    feedButton.text(cartoonSource.getName());

    feedButton.click(selectButtonHandler);
    var removeButton = cartoonSourceElement.find("button[name=remove]");
    
    this.m_dndHelper.disableDragging(removeButton);
    removeButton.click(removeButtonHandler);
    return cartoonSourceElement;
  }
};

function UpdateCartoonSourceAdapter(resultReceiver) {
  this.setResultReceiver(resultReceiver);
  this.m_cartoonSourceResultFiller = new CartoonSourceResultFiller();
}

UpdateCartoonSourceAdapter.prototype = {
  setResultReceiver: function(resultReceiver) {
    this.m_resultReceiver = resultReceiver;
  },
  getResultReceiver: function(receiver) {
    return this.m_resultReceiver;
  },
  receiveResults: function(tx, results) {
    var updated = false;
    if(results.rowsAffected > 0) {
      updated = true;
    }
    this.sendToReceiver(updated);
  },
  getReceiver: function() {
    var callbackObject = { that: this,
                           callback: this.receiveResults};
    return callbackObject;
  },
  sendToReceiver: function(updated) {
    this.m_resultReceiver.callback.call(this.m_resultReceiver.that,
                                        updated);
  }
};
